Linking Shared Libraries

Anyone may build a shared library of Lisp code with the functions define-library and link-library. However, before ld can link a library of Lisp files, the extra linking information that was written during the compilation of the library is used to create additional code and data.


Table: WCL Library and Executable Sizes
Library Text Data File Size
Common Lisp 1351k 311k 2113k
Compiler 868k 221k 1425k
CLXR5 1548k 352k 2400k
Development executable 41k 8k 49k


Every time a Lisp file contains a reference to a Lisp symbol, a reference to the mangled name of the symbol is emitted. However, at some point exactly one correctly initialized instance of the symbol must be created. The Unix linker's concept of a common area provides part of the support necessary to create exactly one symbol, but it lacks support for properly initializing this common area so that the symbol's name, function cell, etc. all contain appropriate values.

To overcome this problem, information about symbol usage in each file is stored in the file's linking information, and exactly one instance of every referenced symbol is written out as a C structure. The slots of this structure are also initialized according to the linking information. For example, if one file defines a function named FOO while another file contains the form (DEFVAR FOO 3), the compiler records these facts in the linkage information for each file. At link time, the function cell of FOO will be initialized to point to the corresponding C code, while the value cell will contain the fixnum 3, thus avoiding any runtime work to initialize these slots. The linker does not currently know how to initialize the package system at link time. Thus, every symbol is interned at runtime in its corresponding package. The garbage collector is also informed about all symbols so that they can be traced.

Linking information about structure definitions is also recorded and used to define efficient structure predicates. In a fluid development environment, a structure predicate may potentially have to examine the structure hierarchy at runtime to determine the type of an object. However, by freezing the structure hierarchy at link time, WCL can create structure predicates that can perform type checks more quickly.

While compiling a Lisp file, every top-level form is collected into an initialization thunk that must be called at runtime to initialize the file, and the name of this thunk is recorded in the linking information. When linking a group of files, a single initialization thunk is defined for all the files, sequentially calling each file's initialization code. In order to ``start'' the whole collection of files, only this single initialization thunk must be called.

Once these extra pieces of code and data have been compiled, everything is linked by ld into a sharable library. Additional information about the procedures and symbols defined in the library is also recorded.